package grouters

import (
	"encoding/xml"
	"errors"
	"reflect"
	"strconv"
	"strings"

	views "gitee.com/abril-cx/gtools/gviews"
	"github.com/gin-gonic/gin"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
)

type HandleRouter struct{}

func (h *HandleRouter) CheckId(req_data *views.RequestData) error {
	if req_data.Id.IsZero() {
		return errors.New("id is empty")
	}
	return nil
}

func CheckRequired(fields []bson.M, req_data *views.RequestData) error {
	for _, v := range fields {
		field := v["field"].(string)
		required := v["required"].(bool)
		value, ok := req_data.Maps[field]
		if !ok {
			if required {
				return errors.New(field)
			}
		} else {
			if value == nil {
				if required {
					return errors.New(field)
				}
			}
			switch reflect.TypeOf(value).Name() {
			case "string":
				if value.(string) == "" {
					return errors.New(field)
				}
			case "int64":
				if value.(int64) == 0 {
					return errors.New(field)
				}
			case "float64":
				if value.(float64) == 0 {
					return errors.New(field)
				}
			}
		}
	}
	return nil
}

func (h *HandleRouter) GetQueryData(ctx *gin.Context, model string) *views.RequestData {
	req_data := GetQueryData(ctx)
	req_data.Model = model
	return req_data
}

func (h *HandleRouter) GetBodyData(ctx *gin.Context, model string) (*views.RequestData, error) {
	req_data, err := GetBodyData(ctx)
	req_data.Model = model
	return req_data, err
}

func GetQueryData(ctx *gin.Context) *views.RequestData {
	req_data := &views.RequestData{}
	req_data.Token = ctx.GetHeader("Authorization")
	datas := map[string]interface{}{}
	for k, v := range ctx.Request.URL.Query() {
		if k == "_id" {
			req_data.Id, _ = primitive.ObjectIDFromHex(v[0])
		} else {
			if v[0] != "" {
				datas[k] = v[0]
			}
		}
	}
	params := &views.DefaultParams{}
	page, ok := datas["page"].(string)
	if ok {
		page, err := strconv.Atoi(page)
		if err != nil {
			params.Page = 1
		} else {
			params.Page = int64(page)
		}
	}
	size, ok := datas["size"].(string)
	if ok {
		size, err := strconv.Atoi(size)
		if err != nil {
			params.Size = 20
		} else {
			params.Size = int64(size)
		}
	}
	order, ok := datas["order"].(string)
	if ok {
		params.Order = order
	}
	sort, ok := datas["sort"].(string)
	if ok {
		params.Sort = sort
	}
	delete(datas, "page")
	delete(datas, "size")
	delete(datas, "sort")
	delete(datas, "order")
	req_data.Datas = datas
	req_data.Params = params
	return req_data
}

func GetBodyData(ctx *gin.Context) (*views.RequestData, error) {
	req_data := &views.RequestData{}
	req_data.Token = ctx.GetHeader("Authorization")
	maps := bson.M{}
	body, _ := ctx.GetRawData()
	err := bson.UnmarshalExtJSON(body, true, &maps)
	if err != nil {
		return req_data, err
	}
	id, ok := maps["_id"].(string)
	if ok {
		req_data.Id, _ = primitive.ObjectIDFromHex(id)
	}
	delete(maps, "_id")
	for k, v := range maps {
		if v == nil {
			// 判断是否为空
			delete(maps, k)
		} else if reflect.TypeOf(v).Name() == "string" && v.(string) == "" {
			// 判断是否为空字符串
			// delete(maps, k)
		} else if reflect.TypeOf(v).Name() == "[]interface {}" && len(v.([]interface{})) == 0 {
			// 判断是否为空数组
			delete(maps, k)
		}
	}
	req_data.Maps = maps
	return req_data, nil
}

func GetXMLData(ctx *gin.Context, v interface{}) error {
	body, err := ctx.GetRawData()
	if err != nil {
		return err
	}
	return xml.Unmarshal(body, v)
}

func GetFileData(ctx *gin.Context, name string) (*views.RequestData, error) {
	req_data := &views.RequestData{}
	req_data.Token = ctx.GetHeader("Authorization")
	file, err := ctx.FormFile(name)
	fileNameList := strings.Split(file.Filename, ".")
	req_data.File = &views.FileHandle{
		FileData: file,
		Suffix:   fileNameList[len(fileNameList)-1],
	}
	return req_data, err
}

func GetFilesData(ctx *gin.Context) (*views.RequestData, error) {
	req_data := &views.RequestData{}
	req_data.Token = ctx.GetHeader("Authorization")
	form, err := ctx.MultipartForm()
	if err != nil {
		return req_data, err
	}
	fileHandle := []*views.FileHandle{}
	for _, file := range form.File["file[]"] {
		fileNameList := strings.Split(file.Filename, ".")
		fileHandle = append(fileHandle, &views.FileHandle{
			FileData: file,
			Suffix:   fileNameList[len(fileNameList)-1],
		})
	}
	req_data.Files = fileHandle
	return req_data, nil
}
